package powershell

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"syscall"
	"unicode/utf8"
	"golang.org/x/text/encoding/simplifiedchinese"
	"pwsh-go/internal/algorithms"
)

// Backend defines the interface for PowerShell execution
type Backend interface {
	Execute(command string) (string, error)
	Close() error
}

type localSession struct{
	// 性能优化组件
	workerPool     *algorithms.WorkerPool
	batchProcessor *algorithms.BatchProcessor
	memoryPool     *algorithms.MemoryPool
}

// NewBackend creates a new PowerShell backend
func NewBackend() (Backend, error) {
	if runtime.GOOS == "windows" {
		// 初始化优化组件
		workerPool := algorithms.NewWorkerPool(2, 50) // 2个工作协程，缓冲区50
		batchProcessor := algorithms.NewBatchProcessor(5, func(batch []interface{}) ([]interface{}, error) {
			// 批处理命令执行逻辑
			return batch, nil
		})
		memoryPool := algorithms.NewMemoryPool(1024) // 1KB缓冲区
		
		session := &localSession{
			workerPool:     workerPool,
			batchProcessor: batchProcessor,
			memoryPool:     memoryPool,
		}
		
		// 启动工作池
		session.workerPool.Start()
		
		return session, nil
	}
	return &MockBackend{}, nil
}

func init() {
	kernel32 := syscall.NewLazyDLL("kernel32.dll")
	procOutput := kernel32.NewProc("SetConsoleOutputCP")
	procInput := kernel32.NewProc("SetConsoleCP")
	procOutput.Call(65001)
	procInput.Call(65001)
}

// Execute runs a command with special handling for ssh
func (s *localSession) Execute(command string) (string, error) {
	if strings.HasPrefix(strings.ToLower(command), "ssh ") {
		return "", s.ExecuteSSH(command)
	}

	cmd := exec.Command("powershell", "-NoLogo", "-Command", command)
	cmd.Env = append(os.Environ(),
		"PATH="+os.Getenv("PATH")+";C:\\Program Files\\Git\\cmd;C:\\Program Files\\Git\\bin",
	)
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err := cmd.Run()
	output := stdout.Bytes()
errorOutput := stderr.Bytes()
decodedOutput, _ := decodeToUTF8(output)
decodedError, _ := decodeToUTF8(errorOutput)

	if err != nil || len(decodedError) > 0 {
		// 检查是否是 git 命令且未找到
		if strings.HasPrefix(strings.ToLower(command), "git ") && (strings.Contains(strings.ToLower(decodedError), "commandnotfoundexception") || strings.Contains(strings.ToLower(decodedOutput), "commandnotfoundexception") || (err != nil && strings.Contains(strings.ToLower(err.Error()), "not found"))) {
		fallbackPath := "C:\\Program Files\\Git\\cmd\\git.exe"
		args := strings.Fields(strings.TrimPrefix(command, "git "))
		cmd = exec.Command(fallbackPath, args...)
		cmd.Env = os.Environ()
		stdout.Reset()
		stderr.Reset()
		cmd.Stdout = &stdout
		cmd.Stderr = &stderr
		err = cmd.Run()
		output = stdout.Bytes()
		errorOutput = stderr.Bytes()
		decodedOutput, _ = decodeToUTF8(output)
		decodedError, _ = decodeToUTF8(errorOutput)
	}
	}

	if err != nil {
		return decodedOutput, fmt.Errorf("execution failed: %w\nStderr: %s", err, decodedError)
	}
	if len(decodedError) > 0 {
		return decodedOutput, fmt.Errorf("stderr: %s", decodedError)
	}
	return strings.TrimSpace(decodedOutput), nil
}

// ExecuteSSH handles ssh commands with TTY
func (s *localSession) ExecuteSSH(cmd string) error {
	parts := strings.Fields(cmd)
	c := exec.Command(parts[0], append([]string{"-tt"}, parts[1:]...)...)
	c.Stdin = os.Stdin
	c.Stdout = os.Stdout
	c.Stderr = os.Stderr
	return c.Run()
}

// decodeToUTF8 decodes bytes from GBK to UTF-8
func decodeToUTF8(data []byte) (string, error) {
	if utf8.Valid(data) {
		return string(data), nil
	}
	decoder := simplifiedchinese.GBK.NewDecoder()
	decoded, err := decoder.Bytes(data)
	if err != nil {
		return string(data), err
	}
	return string(decoded), nil
}

// Close cleans up resources
func (s *localSession) Close() error {
	if s.workerPool != nil {
		s.workerPool.Stop()
	}
	return nil
}

type MockBackend struct{}

func (m *MockBackend) Execute(command string) (string, error) {
	return "", fmt.Errorf("unsupported on %s", runtime.GOOS)
}
func (m *MockBackend) Close() error {
	return nil
}
